home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / SystemCode / templates.tcl < prev    next >
Encoding:
Text File  |  2000-03-19  |  8.5 KB  |  279 lines

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #  AlphaTcl - core Tcl engine
  4.  # 
  5.  #  FILE: "templates.tcl"
  6.  #                                    created: 27/7/97 {9:29:20 pm} 
  7.  #                                last update: 03/19/2000 {14:43:56 PM} 
  8.  #  Author: Vince Darley
  9.  #  E-mail: <vince@santafe.edu>
  10.  #    mail: 317 Paseo de Peralta, Santa Fe, NM 87501
  11.  #     www: <http://www.santafe.edu/~vince/>
  12.  #  
  13.  # Copyright (c) 1997-2000  Vince Darley, all rights reserved
  14.  # 
  15.  # Simple template insertion mechanism.  Can be easily overridden
  16.  # by a more sophisticated scheme providing more features, whilst
  17.  # still working simply if desired.  Call any of these 
  18.  # procs from the outside:
  19.  # 
  20.  #  elec::Insertion args  -- insert the given args
  21.  #  elec::CenterInsertion args -- insert, then center redraw
  22.  #  elec::Wrap left right -- wrap left and right about the selection
  23.  #  
  24.  #  ring::+ -- move to the next template stop
  25.  #  ring::- -- move to the previous template stop
  26.  #  
  27.  # Any piece of text given to the three 'elec::' procs has a template
  28.  # conversion done.  Text of the form '•blah•' is converted to a single
  29.  # bullet '•', with 'blah' attached to it internally.  
  30.  # 
  31.  # A more sophisticated template package, available separately, can
  32.  # prompt the user with 'blah' in useful ways, and creates a proper
  33.  # template ring.
  34.  # 
  35.  #  modified by  rev reason
  36.  #  -------- --- --- -----------
  37.  #  27/7/97  VMD 1.0 original
  38.  # ###################################################################
  39.  ##
  40.  
  41. alpha::flag electricTab 0.1.2 Electrics global help {
  42.     Enabling the 'Electric Tab' feature allows Alpha you to use
  43.     the procedures 'Indent or Next Stop' and 'Tab or Complete' as
  44.     any of your 'Special Keys' bindings.
  45.     
  46.     What these procedures do is change the behaviour of the Tab
  47.     key to depend upon the context.  In other words, hitting Tab
  48.     will not usually insert a Tab, rather it may indent the
  49.     current line, or move to the next Stop mark or complete the
  50.     current text,...
  51.     
  52.     Note that 'cmd-Tab' is one of the possible key-bindings
  53.     used to complete whatever you type.  If you use cmd-Tab as
  54.     a 'program switcher' in MacOS or other software, then you
  55.     obviously cannot use that keybinding in Alpha, since it
  56.     will be intercepted by the operating system.
  57. }
  58.  
  59. namespace eval elec {}
  60. namespace eval bind {}
  61. namespace eval ring {}
  62.  
  63. proc alpha::useElectricTemplates {} {}
  64.  
  65. # The character inserted into the text to indicate 'stop marks': useful
  66. # positions which you can jump between very quickly
  67. newPref variable elecStopMarker "•"
  68.  
  69. ## 
  70.  # -------------------------------------------------------------------------
  71.  #     
  72.  #    "elec::_Insertion" --
  73.  #    
  74.  #  Insert a piece of text, padding on the left appropriately.  The text
  75.  #  should already be correctly indented within itself.
  76.  #     
  77.  #  Any piece of the text of the form '•blah•' is converted into a single
  78.  #  bullet.  A more advanced version of this procedure, available
  79.  #  separately, allows the use of '•blah•' to prompt the user either in the
  80.  #  window, or status line, and makes the template stops permanent entities
  81.  #  so you can cycle back and forth through a template 'ring'. 
  82.  # -------------------------------------------------------------------------
  83.  ##
  84. proc elec::_Insertion { center args } {
  85.     set text [join $args ""]
  86.     set pos [getPos]
  87.     regsub -all "\t" $text [text::Tab] text
  88.     if {[regexp "\[\n\r\]" $text]} {
  89.     regsub -all "\[\n\r\]" $text "\r[text::indentTo $pos]" text
  90.     }
  91.     if {[regexp "…" $text]} {
  92.     regsub -all "…" $text [text::halfTab] text
  93.     }
  94.     setMark
  95.     global elecStopMarker
  96.     if {![regexp "•" $text] || ([regexp {^([^•]*)••$} $text "" text])} {
  97.     insertText $text
  98.     if {$center} { centerRedraw }
  99.     } else {
  100.     regsub -all {•[^•]*•} $text $elecStopMarker text
  101.     insertText $text
  102.     goto $pos
  103.     if {$center} { centerRedraw }
  104.     # need to go to the first tab stop
  105.     ring::+
  106.     }
  107. }
  108.  
  109.  
  110. # ◊◊◊◊ possible tab key bindings ◊◊◊◊ #
  111. # note: Also provided by the base Alpha system, these overide when 
  112. # Univs Completions package is in use (these may be more intricate).
  113.  
  114. ## 
  115.  # -------------------------------------------------------------------------
  116.  #     
  117.  #    "bind::IndentOrNextstop" --
  118.  #    
  119.  #  Either insert a real tab if your mode hasn't defined its electricTab
  120.  #  variable, or jump to the next template stop (if we're mid-template), or
  121.  #  indent the current line correctly.
  122.  #     
  123.  #  If this proc doesn't seem to do the right thing.  Make sure you've got
  124.  #  'electricTab' set correctly in your preferences! 
  125.  # -------------------------------------------------------------------------
  126.  ##
  127. proc bind::IndentOrNextstop {{hard 0}} {
  128.     global electricTab
  129.     if {$hard || !$electricTab} {
  130.     insertActualTab 
  131.     } else {
  132.     if {![ring::+]} {bind::IndentLine}
  133.     }
  134. }
  135.  
  136. ## 
  137.  # -------------------------------------------------------------------------
  138.  #     
  139.  #    "bind::TabOrComplete" --
  140.  #    
  141.  #  Either insert a real tab if your mode hasn't defined its electricTab
  142.  #  variable, or invoke the completion mechanism, or indent the current
  143.  #  line correctly.
  144.  #     
  145.  #  If this proc doesn't seem to do the right thing.  Make sure you've got
  146.  #  'electricTab' set correctly in your preferences! 
  147.  # -------------------------------------------------------------------------
  148.  ##
  149. proc bind::TabOrComplete {{hard 0}} {
  150.     global electricTab
  151.     if {$hard || !$electricTab} {
  152.     insertActualTab 
  153.     } else {
  154.     bind::Completion
  155.     }
  156. }
  157.  
  158. proc ring::+ {} {
  159.     global elecStopMarker
  160.     set pos [getPos]
  161.     if {[pos::compare $pos == [maxPos]]} { return 0 }
  162.     set searchResult [lindex [search -s -n -f 1 -m 0 -i 1 -r 0 $elecStopMarker $pos] 0]
  163.     if {[string length $searchResult]} {
  164.     goto $searchResult
  165.     deleteChar
  166.     return 1
  167.     } else {
  168.     return 0
  169.     }
  170. }
  171.  
  172. proc ring::- {} {
  173.     global elecStopMarker
  174.     set pos [getPos]
  175.     if {[pos::compare $pos == [minPos]]} { return 0 }
  176.     set searchResult [lindex [search -s -n -f 0 -m 0 -i 1 -r 0 $elecStopMarker $pos] 0]
  177.     if {[string length $searchResult]} {
  178.     goto $searchResult
  179.     deleteChar
  180.     return 1
  181.     } else {
  182.     return 0
  183.     }
  184. }
  185.  
  186. # Removes all tab stops from the current selection (if there is one) 
  187. # or the current document, maintaining the cursor position in the 
  188. # latter case.
  189. proc ring::clear {} {
  190.     watchCursor
  191.     set pos [getPos]
  192.     global elecStopMarker
  193.     if {[pos::compare [set start $pos] == [set end [selEnd]]]} {
  194.     set start [minPos]
  195.     set end [maxPos]
  196.     set text1 [getText $start $pos]
  197.     set subs1 [regsub -all -- $elecStopMarker $text1 {} text1]
  198.     set text2 [getText $pos $end]
  199.     set subs2 [regsub -all -- $elecStopMarker $text2 {} text2]
  200.     if {($subs1 == 0) && ($subs2 == 0)} {return}
  201.     append text $text1 $text2
  202.     replaceText $start $end $text
  203.     goto [pos::math $pos - $subs1]
  204.     message "[expr {$subs1 + $subs2}] stops cleared"
  205.     } else {
  206.     set text [getText $start $end]
  207.     set subs3 [regsub -all -- $elecStopMarker $text {} text]
  208.     if {$subs3 == 0} {return}
  209.     replaceText $start $end $text
  210.     set end [getPos]
  211.     select $start $end
  212.     message "$subs3 stops cleared"
  213.     }
  214. }
  215. # indicates we're a very basic ring
  216. proc ring::type {} { return 0 }
  217. proc ring::nth {} {
  218.     message "ring::nth requires the Better Templates feature"
  219. }
  220.  
  221. ## 
  222.  # -------------------------------------------------------------------------
  223.  # 
  224.  # "elec::CenterInsertion" --
  225.  # 
  226.  #  Insert and then do a refresh.  Useful for large electric insertions.
  227.  # -------------------------------------------------------------------------
  228.  ##
  229. proc elec::CenterInsertion {args} {
  230.     eval elec::_Insertion 1 $args
  231. }
  232.  
  233. ## 
  234.  # -------------------------------------------------------------------------
  235.  # 
  236.  # "elec::Insertion" --
  237.  # 
  238.  #  Just insert the electric item
  239.  # -------------------------------------------------------------------------
  240.  ##
  241. proc elec::Insertion { args } {
  242.     eval elec::_Insertion 0 $args
  243. }
  244. proc elec::ReplaceText { start end args } {
  245.     deleteText $start $end 
  246.     eval elec::_Insertion 0 $args
  247. }
  248.  
  249. ## 
  250.  # -------------------------------------------------------------------------
  251.  #     
  252.  #    "elec::Wrap" --
  253.  #    
  254.  #  Currently doesn't deal with indentation -- the wrapper is supposed to
  255.  #  handle that.
  256.  #     
  257.  #  Returns 0/1 to indicate if there was a selection which this proc
  258.  #  wrapped. 
  259.  # -------------------------------------------------------------------------
  260.  ##
  261. proc elec::Wrap { left right {complete 0}} {
  262.     set pos [getPos]
  263.     set s [getSelect]
  264.     if {[string length $s]} {
  265.     deleteText $pos [selEnd]
  266.     elec::Insertion $left $s $right
  267.     return 1
  268.     } else {
  269.     elec::Insertion $left "••" $right
  270.     if {$complete} {
  271.         bind::Completion
  272.     }
  273.     return 0
  274.     }
  275. }
  276.  
  277.  
  278.  
  279.